package com.zkrt.upms.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.zkrt.upms.common.util.DateUtils;
import com.zkrt.upms.common.util.SocketUtil;
import com.zkrt.upms.dto.*;
import com.zkrt.upms.entity.AttributeData;
import com.zkrt.upms.entity.DeviceAttrR;
import com.zkrt.upms.entity.DeviceB;
import com.zkrt.upms.enums.IotHJTypeEnum;
import com.zkrt.upms.mapper.DeviceAttrRMapper;
import com.zkrt.upms.mapper.DeviceBMapper;
import com.zkrt.upms.service.IUpDataService;
import com.zkrt.upms.service.InfluxdbService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class UpDataServiceImpl implements IUpDataService {

    @Value("${sendtask.upload.dataserver.host}")
    private String host;

    @Value("${sendtask.upload.dataserver.port}")
    private Integer port;

    @Value("${rule.data.errorminute}")
    private Integer minute;

    @Autowired
    private DeviceBMapper deviceMapper;

    @Autowired
    private DeviceAttrRMapper attrMapper;

    @Autowired
    private InfluxdbService influxdbService;

    @Value("${sendtask.isInflux}")
    private Integer isInflux;

    private final String dateTimeLong(Long timeStamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timeStamp);
        Date time = calendar.getTime();
        String yyyyMMddHHmmssSSS = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(time);
        return yyyyMMddHHmmssSSS;
    }

    private final String dateTimeSmall(Long timeStamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timeStamp);
        Date time = calendar.getTime();
        String yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss").format(time);
        return yyyyMMddHHmmss;
    }

    /**
     * HJ212重构
     * @return
     */
    private Map<String, HJ212MsgDTO> formatHJ212() {
        final String phFlag = "N"; // PH
        final String swFlag = "N"; // 水温
        final String oFlag = "N"; // 溶氧
        final String phKey = IotHJTypeEnum.PH.getCode();
        final String swKey = IotHJTypeEnum.SW.getCode();
        final String oKey = IotHJTypeEnum.O.getCode();
        final String cn = "2011";
        final String pw = "123456";
        final String flag = "4";
        LambdaQueryWrapper<DeviceB> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.eq(DeviceB::getDisabled, false);
        List<DeviceB> devices = deviceMapper.selectList(deviceWrapper);

        if (devices != null && devices.size() > 0) {
            Long current = System.currentTimeMillis();
            String qn = dateTimeLong(current);
            String dt = dateTimeSmall(current);
            Map<String, HJ212MsgDTO> hj212s = new HashMap<>();
            devices.stream().forEach(d -> {
                HJ212MsgDTO message = hj212s.get(d.getUniqueId());
                if (message == null) {
                    message = new HJ212MsgDTO();
                }
                message.setQn(qn);
                message.setDataTime(dt);
                message.setCn(cn);
                message.setPw(pw);
                message.setFlag(flag);
                message.setMn(d.getUniqueId());
                message.setSt(d.getGwCode());
                LambdaQueryWrapper<DeviceAttrR> attrWrapper = new LambdaQueryWrapper<>();
                attrWrapper.eq(DeviceAttrR::getSn, d.getSn());
                List<DeviceAttrR> attrs = attrMapper.selectList(attrWrapper);

                if (attrs != null && attrs.size() > 0) {
                    for (DeviceAttrR a : attrs) {
                        String key = a.getAttrKey();
                        String value = a.getAttrValue() != null ? a.getAttrValue() : "0";

                        // 修正异常数据值，不在判定范围内的数据，归类为异常数据，不判定硬件情况
                        Calendar calendar = Calendar.getInstance();
                        Date updateTime = a.getUpdateTime(); // 更新数据的时间
                        Calendar updateCalendar = Calendar.getInstance();
                        updateCalendar.setTime(updateTime);
                        int duration = minute != null ? (-1*minute) : -30;
                        calendar.add(Calendar.MINUTE, duration); // 当前时间向前推30分钟
                        if (updateCalendar.before(calendar)) { // 以当前时间的前30分钟判断，不足30分钟的数据判定未异常数据，更定值为0
                            String updateTimeText = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(updateTime);
                            log.error("[数据未实时更新] -> {}", String.format("已超出%s分钟，属性名：%s，数值：%s，最近更新时间：%s", minute, key, value, updateTimeText));
                            value = "0";
                        }

                        if (key.equals(phKey)) { // w01001，PH
                            message.setPhValue(value);
                            message.setPhFlag(phFlag);
                        }
                        if (key.equals(oKey)) { // w01009，溶氧
                            message.setOValue(value);
                            message.setOFlag(oFlag);
                        }
                        if (key.equals(swKey)) { // w01010，水温
                            message.setSwValue(value);
                            message.setSwFlag(swFlag);
                        }
                    }
                }

                hj212s.put(d.getUniqueId(), message);

            });


            Map<String, HJ212MsgDTO> newHj212s = new HashMap<>();

            hj212s.keySet().forEach(s -> {
                HJ212MsgDTO message = hj212s.get(s);

                Integer errSize=0;
                if ("0".equals(message.getPhValue())){
                    errSize++;
                }
                if ("0".equals(message.getOValue())){
                    errSize++;
                }
                if ("0".equals(message.getSwValue())){
                    errSize++;
                }
                if (message.getPhValue()!=null&&message.getOValue()!=null&&message.getSwValue()!=null&&errSize<3){
                    newHj212s.put(s,message);
                }else {
                    log.info("有属性为空或全部为0,不推送:"+message);
                }
            });


            return newHj212s;
        }
        return null;
    }


    private Map<String, HJ212MsgDTO> formatHJ212ByInflux() {
        final String phFlag = "N"; // PH
        final String swFlag = "N"; // 水温
        final String oFlag = "N"; // 溶氧
        final String phKey = IotHJTypeEnum.PH.getCode();
        final String swKey = IotHJTypeEnum.SW.getCode();
        final String oKey = IotHJTypeEnum.O.getCode();
        final String cn = "2011";
        final String pw = "123456";
        final String flag = "4";
        LambdaQueryWrapper<DeviceB> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.eq(DeviceB::getDisabled, false);
        List<DeviceB> devices = deviceMapper.selectList(deviceWrapper);

        if (devices != null && devices.size() > 0) {
            Long current = System.currentTimeMillis();
            String qn = dateTimeLong(current);
            String dt = dateTimeSmall(current);
            Map<String, HJ212MsgDTO> hj212s = new HashMap<>();
            devices.stream().forEach(d -> {
                HJ212MsgDTO message = hj212s.get(d.getUniqueId());
                if (message == null) {
                    message = new HJ212MsgDTO();
                }
                message.setQn(qn);
                message.setDataTime(dt);
                message.setCn(cn);
                message.setPw(pw);
                message.setFlag(flag);
                message.setMn(d.getUniqueId());
                message.setSt(d.getGwCode());

                InfluxNewDto influxNewDto = new InfluxNewDto();
                influxNewDto.setDevSn(d.getSn());
                influxNewDto.setField(d.getAttrKey());
                influxNewDto.setMeasureName(d.getSn());

                AttributeData aNew = influxdbService.getNew(d.getBucket(),influxNewDto);

                aNew.setName((d.getAttrKey()));
                log.info("查询到最新值:"+aNew);
                String key = d.getAttrKey();

                String value = aNew.getValue() != null ? aNew.getValue() : "0";

                // 修正异常数据值，不在判定范围内的数据，归类为异常数据，不判定硬件情况
                Calendar calendar = Calendar.getInstance();

                Date updateTime = aNew.getTheTime()!=null?DateUtils.getDate(aNew.getTheTime()):new Date(); // 更新数据的时间
                Calendar updateCalendar = Calendar.getInstance();
                updateCalendar.setTime(updateTime);
                int duration = minute != null ? (-1*minute) : -30;
                calendar.add(Calendar.MINUTE, duration); // 当前时间向前推30分钟
                if (updateCalendar.before(calendar)) { // 以当前时间的前30分钟判断，不足30分钟的数据判定未异常数据，更定值为0
                    String updateTimeText = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(updateTime);
                    log.error("[数据未实时更新] -> {}", String.format("已超出%s分钟，属性名：%s，数值：%s，最近更新时间：%s", minute, key, value, updateTimeText));
                    value = "0";
                }

                if (key.equals(phKey)) { // w01001，PH
                    message.setPhValue(value);
                    message.setPhFlag(phFlag);
                }
                if (key.equals(oKey)) { // w01009，溶氧
                    message.setOValue(value);
                    message.setOFlag(oFlag);
                }
                if (key.equals(swKey)) { // w01010，水温
                    message.setSwValue(value);
                    message.setSwFlag(swFlag);
                }

                hj212s.put(d.getUniqueId(), message);

            });

            Map<String, HJ212MsgDTO> newHj212s = new HashMap<>();

            hj212s.keySet().forEach(s -> {
                HJ212MsgDTO message = hj212s.get(s);

                Integer errSize=0;
                if ("0".equals(message.getPhValue())){
                    errSize++;
                }
                if ("0".equals(message.getOValue())){
                    errSize++;
                }
                if ("0".equals(message.getSwValue())){
                    errSize++;
                }
                if (message.getPhValue()!=null&&message.getOValue()!=null&&message.getSwValue()!=null&&errSize<3){
                    newHj212s.put(s,message);
                }else {
                    log.info("有属性为空或全部为0,不推送:"+message);
                }
            });


            return newHj212s;
        }
        return null;
    }

    /**
     * 获取HJ212数据
     * @return
     */
    @Override
    public R getHJ212() {
        Map<String, HJ212MsgDTO> hj212s = formatHJ212();
        List<String> results = new ArrayList<>();
        if (hj212s != null) {
            hj212s.forEach((k, message) -> {
                String text = message.getText();
                results.add(text);
            });
        }
        return R.ok(results);
    }

    /**
     * 推送数据至tcp服务
     */
    @Override
    public R upload2Tcp() {
        Map<String, HJ212MsgDTO> hj212s =new HashMap<>();
        if (0==isInflux){
            log.info("步入infulxDB查询");
            hj212s=formatHJ212ByInflux();
        }else {
            hj212s = formatHJ212();

        }
        if (hj212s != null) {
            List<String> results = new ArrayList<>();
            hj212s.forEach((k, message) -> {
                String text = message.getText();
                log.info("[待处理dto内容] -> \n{}", JSONObject.toJSONString(message));
                log.info("[预推送HJ212内容] -> \n{}", text);
                try {
                    String result = SocketUtil.sendMessage(host, port, text);
                    results.add(result);
                } catch (Exception e) {
                    log.error("[HJ212推送异常] -> {}", e.getMessage());
                }
            });
            return R.ok(results);
        }
        return R.failed("推送失败");
    }

    @Override
    public R toData(DeviceAttrSaveDto saveDto) {
        final String phFlag = "N"; // PH
        final String swFlag = "N"; // 水温
        final String oFlag = "N"; // 溶氧
        final String phKey = IotHJTypeEnum.PH.getCode();
        final String swKey = IotHJTypeEnum.SW.getCode();
        final String oKey = IotHJTypeEnum.O.getCode();
        final String cn = "2011";
        final String pw = "123456";
        final String flag = "4";


        Map<String, HJ212MsgDTO> hj212s = new HashMap<>();
        HJ212MsgDTO message = hj212s.get(saveDto.getMn());
        if (message == null) {
            message = new HJ212MsgDTO();
        }


        String time = String.valueOf(new Date().getTime());
        String substring = time.substring(time.length() - 3);

        message.setQn(saveDto.getPushTime()+substring);
        message.setDataTime(saveDto.getPushTime());
        message.setCn(cn);
        message.setPw(pw);
        message.setFlag(flag);
        message.setMn(saveDto.getMn());
        message.setSt(saveDto.getSt());


        for (AttrDto attr : saveDto.getAttrs()) {
            String key = attr.getAttrKey();
            String value = attr.getValue();


            if (key.equals(phKey)) { // w01001，PH
                message.setPhValue(value);
                message.setPhFlag(phFlag);
            }
            if (key.equals(oKey)) { // w01009，溶氧
                message.setOValue(value);
                message.setOFlag(oFlag);
            }
            if (key.equals(swKey)) { // w01010，水温
                message.setSwValue(value);
                message.setSwFlag(swFlag);
            }
        }

        hj212s.put(saveDto.getMn(), message);

        if (hj212s != null) {
            List<String> results = new ArrayList<>();
            hj212s.forEach((k, s) -> {
                String text = s.getText();
                log.info("[实际推送内容] -> \n{}", JSONObject.toJSONString(s));
                log.info("[实际推送HJ212内容] -> \n{}", text);
                try {
                    String result = SocketUtil.sendMessage(host, port, text);
                    results.add(result);
                    log.info("返回报送结果:"+results);
                } catch (Exception e) {
                    log.error("[HJ212推送异常] -> {}", e.getMessage());
                }
            });
            return R.ok(results);
        }

        return null;
    }

    @Override
    public R toDataMs(DeviceAttrSaveMsDto saveDto) {
        final String phFlag = "N"; // PH
        final String swFlag = "N"; // 水温
        final String oFlag = "N"; // 溶氧
        final String phKey = IotHJTypeEnum.PH.getCode();
        final String swKey = IotHJTypeEnum.SW.getCode();
        final String oKey = IotHJTypeEnum.O.getCode();
        final String cn = "2011";
        final String pw = "123456";
        final String flag = "4";


        Map<String, HJ212MsgDTO> hj212s = new HashMap<>();
        HJ212MsgDTO message = hj212s.get(saveDto.getMn());
        if (message == null) {
            message = new HJ212MsgDTO();
        }

        message.setQn(saveDto.getPushTimeMs());
        message.setDataTime(saveDto.getPushTime());
        message.setCn(cn);
        message.setPw(pw);
        message.setFlag(flag);
        message.setMn(saveDto.getMn());
        message.setSt(saveDto.getSt());


        for (AttrDto attr : saveDto.getAttrs()) {
            String key = attr.getAttrKey();
            String value = attr.getValue();


            if (key.equals(phKey)) { // w01001，PH
                message.setPhValue(value);
                message.setPhFlag(phFlag);
            }
            if (key.equals(oKey)) { // w01009，溶氧
                message.setOValue(value);
                message.setOFlag(oFlag);
            }
            if (key.equals(swKey)) { // w01010，水温
                message.setSwValue(value);
                message.setSwFlag(swFlag);
            }
        }

        hj212s.put(saveDto.getMn(), message);

        if (hj212s != null) {
            List<String> results = new ArrayList<>();
            hj212s.forEach((k, s) -> {
                String text = s.getText();
                log.info("[实际推送内容] -> \n{}", JSONObject.toJSONString(s));
                log.info("[实际推送HJ212内容] -> \n{}", text);
                try {
                    String result = SocketUtil.sendMessage(host, port, text);
                    results.add(result);
                    log.info("返回报送结果:"+results);
                } catch (Exception e) {
                    log.error("[HJ212推送异常] -> {}", e.getMessage());
                }
            });
            return R.ok(results);
        }

        return null;
    }

}
